﻿using AutoMapper.Internal.Mappers;
using BW.WMS.WareHouseAllot;
using BW.WMS.WareHouseAllot.Doccode;
using BW.WMS.WareHouseAllot.Interface.Doccode;
using BW.WMS.WareHouseManage;
using BW.WMS.WareHouseStatistics.Page;
using BW.WMS.WareHouseStatistics.StockManagement;
using Microsoft.EntityFrameworkCore;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace BW.WMS.WareHouseStatistics
{
    public class StockManagementAppService : ApplicationService, IStockManagementAppService
    {
        private readonly IRepository<StockManagementModel, Guid> _StockManagementRepository;
        private readonly IRepository<Warehouse, Guid> _warehouseRepository;
        private readonly IRepository<GoodsModel, Guid> _goodsRepository;
        private readonly IRepository<SalesModel, Guid> _salesRepository;
        private readonly IDoccodeService _doccodeService;

        public StockManagementAppService(
            IRepository<StockManagementModel, Guid> StockManagementRepository,
            IRepository<Warehouse, Guid> warehouseRepository,
            IRepository<GoodsModel, Guid> goodsRepository,
            IRepository<SalesModel, Guid> salesRepository,
            IDoccodeService doccodeService)
        {
            _StockManagementRepository = StockManagementRepository;
            _warehouseRepository = warehouseRepository;
            _goodsRepository = goodsRepository;
            _salesRepository = salesRepository;
            _doccodeService = doccodeService;
        }


        /// <summary>
        /// 创建
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<StockManagementDto> CreateAsync(CreateUpdateStockManagementDto input)
        {


            var stock = ObjectMapper.Map<CreateUpdateStockManagementDto, StockManagementModel>(input);

            stock.Stockcode = await _doccodeService.GenerateCodeAsync("入库信息");

            // 1. 根据id查询数据（只查询未删除的数据）
            var code = await _StockManagementRepository.FirstOrDefaultAsync(x => x.Stockcode == input.Stockcode);

            if (code != null)
            {
                throw new ArgumentException("入库单号已存在");
            }

            //随机数
            //Random random = new Random();
            //stock.Stockcode = "PKDH" + random.Next(1000, 10000);
            stock.Stockstate = "待审核";
            stock.IsDeleted = false;

            await _StockManagementRepository.InsertAsync(stock);

            return ObjectMapper.Map<StockManagementModel, StockManagementDto>(stock);
        }
        /// <summary>
        /// 删除（逻辑删除）
        /// </summary>
        /// <param name="id"></param>
        /// <returns>返回操作结果提示信息</returns>
        public async Task DeleteAsync(Guid id)
        {
            // 1. 根据id查询数据（只查询未删除的数据）
            var stock = await _StockManagementRepository.FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

            if (stock != null)
            {
                // 2. 设置IsDeleted为true进行逻辑删除
                stock.IsDeleted = true;
            }
            else
            {
                throw new ArgumentException("未查询到要删除的数据");
            }

            // 3. 更新数据到数据库
            await _StockManagementRepository.UpdateAsync(stock);
        }



        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<StockManagementDto> GetAsync(Guid id)
        {
            var stock = await _StockManagementRepository.FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

            if (stock == null)
            {
                throw new ArgumentException("未查询到数据");
            }

            return ObjectMapper.Map<StockManagementModel, StockManagementDto>(stock);
        }
        /// <summary>
        /// 获取分页列表
        /// </summary>
        /// <param name="input">查询条件和分页参数</param>
        /// <returns>包含分页信息和数据的结果</returns>
        public async Task<PagedResultDto<StockManagementDto>> GetListAsync(StockManagementGetList input)
        {
            // 1. 获取基础查询（只查询未删除的数据）
            var stockQuery = await _StockManagementRepository.GetQueryableAsync();
            stockQuery = stockQuery.Where(x => !x.IsDeleted);

            var warehouseQuery = await _warehouseRepository.GetQueryableAsync();
            var goodsQuery = await _goodsRepository.GetQueryableAsync();
            var salesQuery = await _salesRepository.GetQueryableAsync();

            // 3. 构建左连接查询
            // 使用左连接确保即使关联表没有数据也能返回主表数据
            var query = from stock in stockQuery
                        join warehouse in warehouseQuery on stock.Warehouseid equals warehouse.Id into warehouseJoin
                        from warehouse in warehouseJoin.DefaultIfEmpty()
                        join goods in goodsQuery on stock.GoodsId equals goods.Id into goodsJoin
                        from goods in goodsJoin.DefaultIfEmpty()
                        join sales in salesQuery on stock.Associated equals sales.SalesCode into salesJoin
                        from sales in salesJoin.DefaultIfEmpty()
                        select new
                        {
                            Stock = stock,
                            WarehouseName = warehouse != null ? warehouse.Name : null,
                            GoodsName = goods != null ? goods.GoodsName : null,
                            SalesCode = sales != null ? sales.SalesCode : stock.Associated
                        };

            // 4. 应用查询条件
            if (!string.IsNullOrEmpty(input.Stockcode))
            {
                query = query.Where(x => x.Stock.Stockcode != null && x.Stock.Stockcode.Contains(input.Stockcode));
            }
            if (!string.IsNullOrEmpty(input.Stocktype))
            {
                query = query.Where(x => x.Stock.Stocktype != null && x.Stock.Stocktype.Contains(input.Stocktype));
            }
            if (!string.IsNullOrEmpty(input.Stockstate))
            {
                query = query.Where(x => x.Stock.Stockstate != null && x.Stock.Stockstate.Contains(input.Stockstate));
            }
            if (!string.IsNullOrEmpty(input.Warehouseid) && Guid.TryParse(input.Warehouseid, out var warehouseGuid))
            {
                query = query.Where(x => x.Stock.Warehouseid == warehouseGuid);
            }

            // 5. 获取总记录数
            var totalCount = query.Count();

            // 6. 应用排序和分页
            var items = query
                .OrderByDescending(x => x.Stock.CreationTime)
                .Skip((input.PageIndex - 1) * input.PageSize)
                .Take(input.PageSize)
                .ToList();

            // 7. 映射为DTO并填充关联表信息
            var dtoItems = new List<StockManagementDto>();
            foreach (var item in items)
            {
                var dto = ObjectMapper.Map<StockManagementModel, StockManagementDto>(item.Stock);
                dto.WarehouseName = item.WarehouseName;
                dto.GoodsName = item.GoodsName;
                // Associated字段已经是SalesCode，所以不需要额外映射
                dtoItems.Add(dto);
            }

            // 8. 返回分页结果
            return PagedResultDto<StockManagementDto>.Create(dtoItems, totalCount, input.PageIndex, input.PageSize);
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="id"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<StockManagementDto> UpdateAsync(Guid id, CreateUpdateStockManagementDto input)
        {
            // 1. 根据id查询现有数据（只查询未删除的数据）
            var stock = await _StockManagementRepository.FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

            if (stock == null)
            {
                throw new ArgumentException("未查询到您要修改的数据");
            }


            // 2. 使用AutoMapper将输入的DTO映射到现有实体，更新实体的属性
            ObjectMapper.Map(input, stock);

            // 3. 映射后确保IsDeleted为false（默认值）
            stock.IsDeleted = false;

            // 3. 更新数据到数据库
            await _StockManagementRepository.UpdateAsync(stock);

            // 4. 将更新后的实体映射为DTO并返回
            return ObjectMapper.Map<StockManagementModel, StockManagementDto>(stock);
        }
        /// <summary>
        /// 更新审核状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="Statedesc"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task UpdateAuditAsync(List<Guid> ids, string? Stockstate, string? Statedesc, string? Test3)
        {
            foreach (var id in ids)
            {
                // 1. 根据id查询数据 (只查询未删除的数据)
                var stock = await _StockManagementRepository.FirstOrDefaultAsync(x => x.Id == id && !x.IsDeleted);

                if (stock != null)
                {
                    if (stock.Stockstate == "待审核")
                    {
                        // 2. 设置状态和描述
                        stock.Statedesc = Statedesc;
                        stock.Stockstate = Stockstate;

                        // 审核人
                        stock.Test3 = Test3;
                        // 审核时间
                        stock.LastModificationTime = DateTime.Now;
                    }
                    else
                    {
                        throw new ArgumentException("审核状态不是待审核");
                    }
                }
                else
                {
                    throw new ArgumentException($"未查询到ID为{id}的数据");
                }

                // 3. 更新数据到数据库
                await _StockManagementRepository.UpdateAsync(stock);
            }
        }
        /// <summary>
        /// 导出数据
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<byte[]> ExportDataAsync(StockManagementGetList filter)
        {
            // 1. 获取基础查询（只查询未删除的数据）
            var stockQuery = await _StockManagementRepository.GetQueryableAsync();
            stockQuery = stockQuery.Where(x => !x.IsDeleted);

            var warehouseQuery = await _warehouseRepository.GetQueryableAsync();
            var goodsQuery = await _goodsRepository.GetQueryableAsync();
            var salesQuery = await _salesRepository.GetQueryableAsync();

            // 3. 构建左连接查询
            // 使用左连接确保即使关联表没有数据也能返回主表数据
            var query = from stock in stockQuery
                        join warehouse in warehouseQuery on stock.Warehouseid equals warehouse.Id into warehouseJoin
                        from warehouse in warehouseJoin.DefaultIfEmpty()
                        join goods in goodsQuery on stock.GoodsId equals goods.Id into goodsJoin
                        from goods in goodsJoin.DefaultIfEmpty()
                        join sales in salesQuery on stock.Associated equals sales.SalesCode into salesJoin
                        from sales in salesJoin.DefaultIfEmpty()
                        select new
                        {
                            Stock = stock,
                            WarehouseName = warehouse != null ? warehouse.Name : null,
                            GoodsName = goods != null ? goods.GoodsName : null,
                            SalesCode = sales != null ? sales.SalesCode : stock.Associated
                        };

            // 4. 应用查询条件
            if (!string.IsNullOrEmpty(filter.Stockcode))
            {
                query = query.Where(x => x.Stock.Stockcode != null && x.Stock.Stockcode.Contains(filter.Stockcode));
            }
            if (!string.IsNullOrEmpty(filter.Stocktype))
            {
                query = query.Where(x => x.Stock.Stocktype != null && x.Stock.Stocktype.Contains(filter.Stocktype));
            }
            if (!string.IsNullOrEmpty(filter.Stockstate))
            {
                query = query.Where(x => x.Stock.Stockstate != null && x.Stock.Stockstate.Contains(filter.Stockstate));
            }
            if (!string.IsNullOrEmpty(filter.Warehouseid) && Guid.TryParse(filter.Warehouseid, out var warehouseGuid))
            {
                query = query.Where(x => x.Stock.Warehouseid == warehouseGuid);
            }


            var data = await query.ToListAsync();

            // 使用 EPPlus 生成 Excel 文件
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial; // 设置许可证上下文

            using (var package = new ExcelPackage())
            {
                var worksheet = package.Workbook.Worksheets.Add("入库统计");

                // 设置标题行
                worksheet.Cells[1, 1].Value = "入库单号";
                worksheet.Cells[1, 2].Value = "入库类型";
                worksheet.Cells[1, 3].Value = "关联单号";
                worksheet.Cells[1, 4].Value = "仓库名称";
                worksheet.Cells[1, 5].Value = "入库日期";
                worksheet.Cells[1, 6].Value = "经办人";
                worksheet.Cells[1, 7].Value = "联系方式";
                worksheet.Cells[1, 8].Value = "货品名称";
                worksheet.Cells[1, 9].Value = "入库数量";

                // 设置标题行样式
                using (var range = worksheet.Cells[1, 1, 1, 11])
                {
                    range.Style.Font.Bold = true;
                    range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
                    range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray);
                }

                // 填充数据
                for (int i = 0; i < data.Count; i++)
                {
                    var item = data[i];
                    int row = i + 2; // 从第2行开始（第1行是标题）

                    // 所以正确的访问方式应该是：
                    worksheet.Cells[row, 1].Value = item.Stock.Stockcode ?? "";
                    worksheet.Cells[row, 2].Value = item.Stock.Stocktype ?? "";
                    worksheet.Cells[row, 3].Value = item.Stock.Associated ?? "";
                    worksheet.Cells[row, 4].Value = item.WarehouseName ?? "";
                    worksheet.Cells[row, 5].Value = item.Stock.Stocktime.ToString("yyyy-MM-dd");
                    worksheet.Cells[row, 6].Value = item.Stock.Agent ?? "";
                    worksheet.Cells[row, 7].Value = item.Stock.Phone ?? "";
                    worksheet.Cells[row, 8].Value = item.GoodsName ?? "";
                    worksheet.Cells[row, 9].Value = item.Stock.Stocknumber ?? 0;
                }

                // 自动调整列宽
                worksheet.Cells.AutoFitColumns();

                // 返回 Excel 文件的字节数组
                return package.GetAsByteArray();
            }

        }
    }
}
